package Execute.MiniSQL.module;

import Execute.MiniSQL.TableManager;
import Execute.MiniSQL.Transformer;

import java.io.IOException;
import java.io.RandomAccessFile;
import java.nio.charset.StandardCharsets;
import java.util.HashMap;
import java.util.Map;

public class Insert {
    public String tableName;        // 表名
    public String values;           // 值
    public String path;             // 插入数据表的路径
    public Map<Integer, String> map;      // 记录每个位置对应的数据类型

    public Insert(String tableName, String values) {
        this.tableName = tableName;
        this.values = values;       // v1_,_v2_,_'v3'
        this.map = new HashMap<>();

        // 插入前需先检查值的个数、类型和表结构是否一致
        if(check()){
            execute();
        }
    }

    /*
    * 判断值的个数、类型和表结构是否一致
    * */
    public boolean check() {
        // 获取表结构
        String v = TableManager.preDesc(tableName);     // v = "Student id int Height decimal name varchar(20)"
        String[] t = v.split(" ");

        String[] myv = values.split(",");         //v1_,_v2_,_v3 ---> v1_    _v2_     _'v3'
        if (myv.length != ((t.length-1)/2)) {
            System.out.println("您想插入的数据值数量与表结构不匹配。应为 " + (t.length-1)/2 + " 个值。而您只提供了 " + myv.length + " 个。");
            return false;
        }
        int j = 0;
        for (int i = 2; i < t.length; i += 2) {
            j = i / 2 - 1;      // 对应值在myv中的下标
            switch (t[i].toLowerCase()) {
                case "int":
                    try {
                        int m = Integer.parseInt(myv[j].trim());
                        map.put(j, "int");
                    } catch (Exception e) {
                        System.out.println("您提供的第" + (j+1) + "个值不能转换为整数");
                        return false;
                    }
                    break;
                case "decimal":
                    try {
                        double d = Double.parseDouble(myv[j].trim());
                        map.put(j, "decimal");
                    } catch (Exception e) {
                        System.out.println("您提供的第" + (j+1) + "个值不能转换为小数");
                        return false;
                    }
                    break;
                default:
                    try {
                        String s = myv[j].trim();           // s = "'v3'"
                        if (s.startsWith("'") && s.endsWith("'")) {
                            int LEN = TableManager.getVarchar(t[i]);
                            int len = s.length() - 2;       // 减去两个引号算出字符长度
                            if(len > LEN) {
                                System.out.println("您提供的第" + (j+1) + "个字符串长度已达 " + len + " 超过该数据表此列的可接收最大长度 " + LEN);
                                return false;
                            }
                            map.put(j, String.valueOf(LEN));
                        }else{
                            System.out.println("您提供的第" + (j+1) + "个字符串格式不对，应该用英文单引号包裹");
                            return false;
                        }
                    } catch (Exception e) {
                        System.out.println("您提供的第" + (j+1) + "个值不能转换为小数");
                        return false;
                    }
                    break;
            }
        }
        return true;

    }

    /*
    * 执行插入
    * */
    public void execute() {
        path = TableManager.DATA_PATH + "/" + tableName + ".midb";
        RandomAccessFile raf = null;
        try {
            raf = new RandomAccessFile(path, "rw");
            // 获取文件长度（字节数）
            long length = raf.length();
            // 将写文件指针移动到文件尾
            raf.skipBytes((int)length);
            String[] v = values.split(",");     //v1_,_v2_,_v3 ---> v1_    _v2_     _'v3'
            for(int i = 0; i < v.length; i++) {
                // 值写入
                valueInsert(raf, i, v[i].trim());
            }
            raf.write("\r\n".getBytes());
            System.out.println("向数据表 " + tableName + " 写入一条数据成功！");
        } catch (Exception e){
            e.printStackTrace();
        } finally {
            if(raf != null){
                try {
                    raf.close();
                }catch (Exception e1){
                    e1.printStackTrace();
                }
            }
        }
    }

    /*
    * 将数据插入表
    * raf 流
    * i 位置对应数据类型
    * s 值的字符串形式      int/double: "v1"    string: "'v3'"
    * */
    public void valueInsert(RandomAccessFile raf, int i, String s) throws IOException {
        String type = map.get(i);
        if (type.equals("int")) {
            // 占4个字节
            int k = Integer.parseInt(s);
            byte[] bytes = Transformer.intToBytes(k);
            raf.write(bytes);
        }else if(type.equals("decimal")) {
            double d = Double.parseDouble(s);
            byte[] bytes = Transformer.doubleToBytes(d);
            raf.write(bytes);
        }else {
            int len = Integer.parseInt(type);
            // 去掉字符串的前后引号
            s = s.substring(s.indexOf("'")+1, s.length()-1);
            // 长度不够则在末尾用空格补齐
            byte[] bytes = s.getBytes(StandardCharsets.UTF_8);
            while (bytes.length != 3*len) {
                s += " ";
                bytes = s.getBytes(StandardCharsets.UTF_8);
            }
            raf.write(bytes);
        }
    }
}
